using System;
using System.Runtime.InteropServices;

namespace NTrace
{
    internal struct ClassicTraceHandle
    {
        private const Int64 EmptyHandle = 0;
        private Int64 sessionHandle;

        public ClassicTraceHandle(Int64 handle)
        {
            this.sessionHandle = handle;
        }

        internal class ClassicTraceHandleMarshaler : ICustomMarshaler
        {
            private static readonly int SizeOfInt64 = 8;
            private static System.Collections.Generic.Dictionary<String, ClassicTraceHandleMarshaler> instances =
                new System.Collections.Generic.Dictionary<string, ClassicTraceHandleMarshaler>();

            public ClassicTraceHandleMarshaler()
            {
            }

            public static ICustomMarshaler GetInstance(String cookie)
            {
                if (!ClassicTraceHandleMarshaler.instances.ContainsKey(cookie))
                {
                    ClassicTraceHandleMarshaler temp = new ClassicTraceHandleMarshaler();
                    ClassicTraceHandleMarshaler.instances[cookie] = temp;
                }
                return ClassicTraceHandleMarshaler.instances[cookie];
            }

            public void CleanUpManagedData(object ManagedObj)
            {
                // NOP
            }

            public void CleanUpNativeData(IntPtr pNativeData)
            {
                if (pNativeData != IntPtr.Zero)
                {
                    Marshal.FreeHGlobal(pNativeData);
                }
            }

            public int GetNativeDataSize()
            {
                return ClassicTraceHandleMarshaler.SizeOfInt64;
            }

            public IntPtr MarshalManagedToNative(object managedObject)
            {
                if (managedObject == null) return IntPtr.Zero;

                if (!(managedObject is ClassicTraceHandle)) throw new ArgumentException("The supplied parameter must be a ClassicTraceHandle.", "managedObject");
                ClassicTraceHandle target = (ClassicTraceHandle)managedObject;

                IntPtr output = Marshal.AllocHGlobal(this.GetNativeDataSize());
                Marshal.WriteInt64(output, target.sessionHandle);
                return output;
            }

            public object MarshalNativeToManaged(IntPtr pNativeData)
            {
                if (pNativeData == IntPtr.Zero) return null;

                Int64 handle = Marshal.ReadInt64(pNativeData);
                ClassicTraceHandle output = new ClassicTraceHandle(handle);
                return output;
            }
        }
    }
}
